home *** CD-ROM | disk | FTP | other *** search
- // npx.cpp - Non-Preemptive eXecutive
- // Copyright 1990 by Cnapse
- // Written by: M. de Champlain
-
- #include <stdio.h>
- #include <stdlib.h>
-
- #include "npx.hpp"
-
- Task *running;
-
- // ---- base class StateQ -------------------
- class StateQ {
- friend class ReadyQ;
- Task *header;
- taskState state;
- public:
- StateQ(int nTasks, taskState st);
- void Insert(Task *thisTask);
- void Transfer(Task *thisTask);
- ~StateQ( );
- };
-
- inline StateQ::StateQ(int nTasks, taskState st)
- {
- header = List_Allocate(nTasks, sizeof(Task));
- state = st;
- }
-
- inline void StateQ::Insert(Task *thisTask)
- {
- thisTask->state = state;
- List_InsertTail(thisTask, header);
- }
-
- inline void StateQ::Transfer(Task *thisTask)
- {
- thisTask->state = state;
- List_Remove(thisTask);
- List_InsertTail(thisTask, header);
- }
-
- inline StateQ::~StateQ()
- {
- List_Free( header );
- }
-
- // ---- derived class ReadyQ -------------------
-
- class ReadyQ : StateQ {
- public:
- ReadyQ() : StateQ(0, READY) {}
- void GetNextRunning(void);
- };
-
- inline void ReadyQ::GetNextRunning(void)
- {
- (running = List_RemoveHead(header))->state = RUNNING;
- }
-
- StateQ *terminatedQ, *suspendedQ;
- ReadyQ *readyQ;
-
- Task *Task::Start(void)
- {
- if (stackBase = new word[stackSizeInBytes/2])
- {
- /* establish new task's SP */
- sp = (reg)((word)stackBase + stackSizeInBytes);
- *--sp = (word) taskStartingAddress;
- --sp; /* push bp */
- parent = running;
- self = this;
- readyQ->Insert(this);
- return self;
- }
- else
- return 0;
- }
-
- Task *Task::Self(void)
- {
- return self;
- }
-
- Task *Task::Parent(void)
- {
- return parent;
- }
-
- void Task::Schedule(void)
- {
- readyQ->GetNextRunning(); // assume at least one task is READY
- }
-
- extern void ContextSwitch(void);
- extern void RunNext(void);
- reg *addrRunningTcbSp;
-
- void Task::ReSchedule(void)
- {
- // save the address of the runningTcb's stack ptr for ContextSwitch.
- addrRunningTcbSp = &running->sp;
- // put the running task in the READY queue
- readyQ->Insert(running);
- Schedule();
- ContextSwitch();
- }
-
- void Task::Terminate(Task *id)
- {
- if ( id->state != TERMINATED )
- {
- delete id->stackBase;
- terminatedQ->Transfer(id);
- delete id;
- if ( id == running )
- {
- Schedule();
- RunNext();
- // should never back here
- }
- }
- }
-
- void Task::Suspend(Task *id)
- {
- if ( id->state != SUSPENDED )
- {
- suspendedQ->Transfer(id);
- if ( id == running )
- {
- // save address of the runningTcb's stack ptr for ContextSwitch.
- addrRunningTcbSp = &running->sp;
- Schedule();
- ContextSwitch();
- // will come back here after a Resume
- }
- }
- }
-
- void Task::Resume(Task *id)
- {
- if ( id->state == SUSPENDED )
- readyQ->Transfer(id);
- }
-
- extern void StartUpUserTasks(void);
-
- main(void)
- {
- printf("Non-Preemptive eXecutive, Copyright 1990 by Cnapse\n\n");
- terminatedQ = new StateQ(10, TERMINATED );
- suspendedQ = new StateQ( 0, SUSPENDED );
- readyQ = new ReadyQ();
-
- // Make StartUpUserTasks RUNNING
- (new Task(StartUpUserTasks, 1024))->Start();
- readyQ->GetNextRunning();
- RunNext();
- }
-